﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Collections;
using System.Collections.ObjectModel;
using System.Windows.Automation.Provider;
using System.Windows.Automation;

namespace TreeControl
{
    [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
    public class MeasurementItem : IDisposable
    {
        #region Fields
        #region Readonly Fields
        private static readonly Image ourCheckedIcon = Configurations.CheckedIcon;
        private static readonly Image ourUncheckedIcon = null;
        private static readonly Image ourActiveIcon = Configurations.ActiveIcon;
        private static readonly Image ourFailedIcon = Configurations.FailedIcon;
        private static readonly Image ourAutoEnabledIcon = Configurations.AutoIcon;
        private static readonly Image ourAutoDisabledIcon = Configurations.DisabledAutoIcon;
        private static readonly Image ourSeriesIcon = Configurations.SeriesIcon;
        private static readonly Image ourCollapsedIcon = Configurations.CollapsedIcon;
        private static readonly Image ourExpandedIcon = Configurations.ExpandedIcon;
        #endregion

        #region Paint Objects
        private Image myStateIcon;
        private Image myExpandCollapseIcon;
        private Image myAutoMeasurementIcon;
        private Image mySeriesIcon;

        private Color myBackColor;

        private Brush myTextBrush;
        private Brush myBackColorBrush;
        #endregion

        #region Rectangles
        private Rectangle myItemBounds;
        private Rectangle myStateRectangle;
        private Rectangle myExpandCollapseRectangle;
        private Rectangle myAutoIconRectangle;
        private Rectangle myAutoIconInflatedRectangle;
        private Rectangle myTextRectangle;
        private Rectangle mySeriesIconRectangle;
        private Rectangle mySeriesIconInflatedRectangle;
        #endregion

        private bool myIsDisposed;
        private bool myIsExpanded;
        private bool myIsEnabled;
        private bool myIsSelected;
        private bool myValuesAreCalculated;
        private bool myNeedToolTip;

        private string myLabel;

        private int myIndent;
        private StringFormat myDrawFormat;
        private State myItemState;
        private Behavior myBehavior;

        private Bitmap myGraphicsCreatorBitmap = new Bitmap(10, 10);
        #endregion

        #region Constructors
        public MeasurementItem(string id, string displayName, MeasurementType type, Behavior behavior, int width, int locationY)
        {
            this.Id = id;
            this.IdFromXmlMatadata = id;
            this.Label = displayName;
            this.MeasurementType = type;
            this.Behavior = behavior;
            this.Width = width;
            this.LocationY = locationY;

            this.IsEnabled = true;

            Height = Configurations.ItemHeight;
            Indent = Configurations.IndentForChildMeasurement;
        }
        #endregion

        #region Properties
        public string ToolTip
        {
            get
            {
                if (myNeedToolTip)
                {
                    return this.Label;
                }
                return this.Label;
            }
        }

        public Control Parent { get; set; }

        public Color BackColor
        {
            get
            {
                return myBackColor;
            }
            set
            {
                myBackColor = value;
                SetBrushColor();
            }
        }

        public int LocationY { get; set; }

        public int Width { get; set; }

        public int Height { get; set; }

        public int Indent
        {
            get
            {
                return myIndent;
            }
            set
            {
                if (myIndent == value)
                {
                    return;
                }
                myIndent = value;
                myValuesAreCalculated = false;
            }
        }

        public string Id { get; set; }

        public string IdFromXmlMatadata { get; set; }

        public string Label
        {
            get
            {
                return myLabel;
            }
            set
            {
                myLabel = value;
                myValuesAreCalculated = false;
                CalculateRectangles();
                if (this.Parent != null)
                {
                    this.Parent.Invalidate(myTextRectangle);
                }
            }
        }

        public MeasurementType MeasurementType { get; set; }

        public Behavior Behavior
        {
            get
            {
                return myBehavior;
            }
            set
            {
                myBehavior = value;
                SetBehaviorIcon(myBehavior);
            }

        }

        public bool IsAutoIconEnabled { get; set; }

        public bool IsExpanded
        {
            get
            {
                return myIsExpanded;
            }
            set
            {
                myIsExpanded = value;
                myExpandCollapseIcon = myIsExpanded ? Configurations.ExpandedIcon : Configurations.CollapsedIcon;
            }
        }

        public bool IsSelected
        {
            get
            {
                return myIsSelected;
            }
            set
            {
                myIsSelected = value;
                SetBrushColor();
                DrawLabel(Graphics.FromImage(myGraphicsCreatorBitmap));
            }
        }

        public bool NeedToolTip { get; set; }

        public bool IsEnabled
        {
            get
            {
                return myIsEnabled;
            }
            set
            {
                myIsEnabled = value;
                SetAutoMeasurementIcon(myIsEnabled);
                SetBrushColor();
            }
        }

        public State ItemState
        {
            get
            {
                return myItemState;
            }
            set
            {
                myItemState = value;
                SetStateIcon(myItemState);
            }
        }

        public Rectangle BoundingRectangle
        {
            get
            {
                return myItemBounds;
            }
        }

        public Rectangle LabelBounds
        {
            get
            {
                return myTextRectangle;
            }
        }

        public Rectangle AutoIconBounds
        {
            get
            {
                return myAutoIconRectangle;
            }
        }

        public Rectangle StateIconBounds
        {
            get
            {
                return myStateRectangle;
            }
        }

        public Rectangle ExpandIconBounds
        {
            get
            {
                return myExpandCollapseRectangle;
            }
        }
        #endregion

        #region Methods
        #region Public Methods
        /// <summary>
        /// 
        /// </summary>
        /// <param name="hitPoint"></param>
        /// <returns></returns>
        public HitArea GetHitArea(Point hitPoint)
        {
            if (MeasurementType == MeasurementType.MeasurementGroup &&
                myExpandCollapseRectangle.Contains(hitPoint))
            {
                return HitArea.ExpandIcon;
            }

            if (myTextRectangle.Contains(hitPoint))
            {
                return HitArea.Label;
            }

            if (IsAutoIconEnabled == true &&
                (Behavior != Behavior.Auto || Behavior != Behavior.AutoSeries) &&
                myAutoIconRectangle.Contains(hitPoint))
            {
                return HitArea.AutoIcon;
            }

            return HitArea.None;
        }
        #endregion

        #region Internal Methods
        internal void Draw(Graphics graphics)
        {
            if (myValuesAreCalculated)
            {
                if (!myIsDisposed)
                {
                    //State Icon
                    DrawStateIcon(graphics);

                    //Expanded Icon
                    if (this.MeasurementType == MeasurementType.MeasurementGroup)
                    {
                        DrawExpandIcon(graphics);
                    }

                    // Auto Icon
                    if (this.Behavior == Behavior.Auto || this.Behavior == Behavior.AutoSeries)
                    {
                        DrawAutoIcon(graphics);
                    }

                    // Label
                    DrawLabel(graphics);

                    //Series Icon
                    if (this.Behavior == Behavior.Series || this.Behavior == Behavior.AutoSeries)
                    {
                        DrawSeriesIcon(graphics);
                    }
                }
            }
        }

        internal void CalculateRectangles()
        {
            CalculateRectangles(Graphics.FromImage(myGraphicsCreatorBitmap));
        }

        internal void SetParent(Control parent)
        {
            this.Parent = parent;
        }

        #endregion

        #region Private Methods
        private void DrawLabel(Graphics graphics)
        {
            graphics.FillRectangle(myBackColorBrush, myTextRectangle);
            graphics.DrawString(this.Label, Configurations.Font, myTextBrush, myTextRectangle, myDrawFormat);
        }

        private void DrawStateIcon(Graphics graphics)
        {
            // State icon - unchecked, active, checked            
            if (myStateIcon != null)
            {
                graphics.DrawImage(myStateIcon, myStateRectangle);
            }
        }

        private void DrawAutoIcon(Graphics graphics)
        {
            if (myAutoMeasurementIcon != null)
            {
                graphics.DrawImage(myAutoMeasurementIcon, myAutoIconInflatedRectangle);
            }
        }

        private void DrawSeriesIcon(Graphics graphics)
        {
            if (mySeriesIcon != null)
            {
                graphics.DrawImage(mySeriesIcon, mySeriesIconInflatedRectangle);
            }
        }

        private void DrawExpandIcon(Graphics graphics)
        {
            int CentreLocationY = (Configurations.IconDefaultSize.Height - myExpandCollapseIcon.Height) / 2;

            GraphicsUnit imageGraphicsUnit = GraphicsUnit.Pixel;
            graphics.DrawImage(myExpandCollapseIcon, myExpandCollapseRectangle.Left + ((myExpandCollapseRectangle.Width -
                myExpandCollapseIcon.Width) / 2), myExpandCollapseRectangle.Top + CentreLocationY,
                myExpandCollapseIcon.GetBounds(ref imageGraphicsUnit),
                GraphicsUnit.Pixel);

        }

        private void SetAutoMeasurementIcon(bool myIsEnabled)
        {
            myAutoMeasurementIcon = (IsEnabled == true) ? ourAutoEnabledIcon : ourAutoDisabledIcon;
        }

        private void SetBehaviorIcon(Behavior myBehavior)
        {
            mySeriesIcon = null;
            switch (myBehavior)
            {
                case Behavior.Series:
                    mySeriesIcon = ourSeriesIcon;
                    break;
                case Behavior.AutoSeries:
                    mySeriesIcon = ourSeriesIcon;
                    myAutoMeasurementIcon = ourAutoEnabledIcon;
                    break;
                case Behavior.Auto:
                    myAutoMeasurementIcon = ourAutoEnabledIcon;
                    break;
            }
        }

        private void SetStateIcon(State myLabelState)
        {
            switch (myLabelState)
            {
                case State.Unchecked:
                    myStateIcon = ourUncheckedIcon;
                    break;
                case State.Active:
                    myStateIcon = ourActiveIcon;
                    break;
                case State.Checked:
                    myStateIcon = ourCheckedIcon;
                    break;
                case State.Failed:
                    myStateIcon = ourFailedIcon;
                    break;
            }
        }

        private void SetBrushColor()
        {
            IList<IDisposable> brushes = new List<IDisposable>(2);
            if (myBackColorBrush != null)
            {
                brushes.Add(myBackColorBrush);
            }
            if (myTextBrush != null)
            {
                brushes.Add(myTextBrush);
            }

            Color color = IsEnabled ? Configurations.MenuItemTextColor : Configurations.MenuItemTextColorDisabled;
            myTextBrush = new SolidBrush(color);

            color = IsEnabled ? Configurations.MenuItemBackColor : Configurations.MenuItemBackColorDisabled;
            if (!color.Equals(BackColor))
            {
                color = BackColor;
            }
            Color labelBackgroundColor = IsSelected ? Configurations.MenuItemBackColorSelected : color;
            myBackColorBrush = new SolidBrush(labelBackgroundColor);

            foreach (IDisposable paintObject in brushes)
            {
                paintObject.Dispose();
            }
            brushes.Clear();
        }

        private void CalculateRectangles(Graphics graphics)
        {
            if (!myValuesAreCalculated)
            {
                int correctedLocationY = LocationY + ((Configurations.ItemHeight - Configurations.IconDefaultSize.Height) / 2);
                Point location = new Point(Configurations.StateIconStartX + Indent, correctedLocationY);
                Size iconDefaultSize = Configurations.IconDefaultSize;
                myStateRectangle = new Rectangle(location, iconDefaultSize);

                int gap = Configurations.GapBetweenIcons;

                myExpandCollapseRectangle = new Rectangle(myStateRectangle.Right, myStateRectangle.Top, 0, 0);
                if (this.MeasurementType == MeasurementType.MeasurementGroup)
                {
                    myExpandCollapseRectangle.Size = iconDefaultSize;
                }

                myAutoIconRectangle = new Rectangle(myExpandCollapseRectangle.Right, myExpandCollapseRectangle.Top, 0, 0);
                if (this.Behavior == Behavior.Auto || this.Behavior == Behavior.AutoSeries)
                {
                    myAutoIconRectangle.Location = new Point(myAutoIconRectangle.Left + gap, myAutoIconRectangle.Top);
                    myAutoIconRectangle.Size = iconDefaultSize;
                }
                myAutoIconInflatedRectangle = myAutoIconRectangle;
                int inflation = Configurations.AutoIconInflate;
                myAutoIconInflatedRectangle.Inflate(inflation, inflation);

                int gapForSeriesIcon = 0;
                if (this.Behavior == Behavior.Series || this.Behavior == Behavior.AutoSeries)
                {
                    gapForSeriesIcon = iconDefaultSize.Width;
                }

                //Drawing the text.  No wrapping.
                Size textSize = Size.Ceiling(graphics.MeasureString(Label, Configurations.Font));
                int allowedWidth = ((this.Width - myAutoIconRectangle.Right) - (Configurations.GapForVerticalScroll + gapForSeriesIcon + gap));
                if (textSize.Width > allowedWidth)
                {
                    textSize.Width = allowedWidth;
                    myNeedToolTip = true;
                }
                int top = (Configurations.ItemHeight - textSize.Height) / 2;
                myTextRectangle = new Rectangle(myAutoIconRectangle.Right + gap, LocationY + top, textSize.Width,
                    textSize.Height);

                mySeriesIconRectangle = new Rectangle(myTextRectangle.Right, myExpandCollapseRectangle.Top, 0, 0);
                if (this.Behavior == Behavior.Series || this.Behavior == Behavior.AutoSeries)
                {
                    mySeriesIconRectangle.Location = new Point(mySeriesIconRectangle.Left + gap, mySeriesIconRectangle.Top);
                    mySeriesIconRectangle.Size = iconDefaultSize;
                }
                mySeriesIconInflatedRectangle = mySeriesIconRectangle;
                inflation = Configurations.SeriesIconInflate;
                mySeriesIconInflatedRectangle.Inflate(inflation, inflation);
                // To fix the icon vertical spacing. There is 1 pixel gap at top between icon and icon file border.
                mySeriesIconInflatedRectangle.Location = new Point(mySeriesIconInflatedRectangle.Left, mySeriesIconInflatedRectangle.Top - 1);

                myItemBounds = new Rectangle(0, LocationY, Width, Height);

                myDrawFormat = new StringFormat();
                myDrawFormat.Alignment = StringAlignment.Near;
                myDrawFormat.LineAlignment = StringAlignment.Center;
                myDrawFormat.Trimming = StringTrimming.EllipsisCharacter;
                myDrawFormat.FormatFlags = StringFormatFlags.NoWrap;

                myExpandCollapseIcon = ourCollapsedIcon;

                myValuesAreCalculated = true;
            }
        }
        #endregion
        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            myIsDisposed = true;
            if (myGraphicsCreatorBitmap != null)
            {
                myGraphicsCreatorBitmap.Dispose();
                myGraphicsCreatorBitmap = null;
            }

            if (myTextBrush != null)
            {
                myTextBrush.Dispose();
                myTextBrush = null;
            }

            if (myBackColorBrush != null)
            {
                myBackColorBrush.Dispose();
                myBackColorBrush = null;
            }
        }

        #endregion

        #region Automation Framework Related Methods
        public MeasurementItem[] Items { get; set; }
        #endregion
    }
}
